package etnorservice.etnor_service.utils;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import etnorservice.etnor_service.domain.GitAuthConfig;
import etnorservice.etnor_service.emus.AuthType;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.TransportCommand;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.eclipse.jgit.transport.*;
//import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory;
//import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig;
import org.eclipse.jgit.util.FS;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class GitUtils {

    public static Git cloneRepository(String repoUrl, String branch, String targetPath, GitAuthConfig auth) throws Exception {
        var cloneCommand = Git.cloneRepository()
                .setURI(repoUrl)
                .setBranch(branch)
                .setDirectory(new File(targetPath));

        configureAuth(cloneCommand, auth);

        return cloneCommand.call();
    }

    public static List<String> listBranches(String repoUrl, GitAuthConfig auth) throws Exception {
        List<String> branches = new ArrayList<>();
        var lsRemoteCommand = Git.lsRemoteRepository()
                .setHeads(true)
                .setTags(false)
                .setRemote(repoUrl);

        configureAuth(lsRemoteCommand, auth);

        var refs = lsRemoteCommand.call();
        refs.forEach(ref -> {
            String branchName = ref.getName().replace("refs/heads/", "");
            branches.add(branchName);
        });

        return branches;
    }

    public static void configureAuth(TransportCommand<?, ?> command, GitAuthConfig auth) {
        if (auth == null || auth.getType() == AuthType.NONE) {
            return;
        }

        switch (auth.getType()) {
            case PASSWORD:
                command.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
                        auth.getUsername(),
                        auth.getPassword()
                ));
                break;

            case TOKEN:
                command.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
                        "token",
                        auth.getToken()
                ));
                break;

            case SSH:
                command.setTransportConfigCallback(new TransportConfigCallback() {
                    @Override
                    public void configure(Transport transport) {
                        if (transport instanceof SshTransport) {
                            configureSshTransport((SshTransport) transport, auth);
                        }
                    }
                });
                break;
        }
    }

    private static void configureSshTransport(SshTransport sshTransport, GitAuthConfig auth) {
        try {
            JschConfigSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
                @Override
                protected void configure(OpenSshConfig.Host host, Session session) {
                    session.setConfig("StrictHostKeyChecking", "no");
                }

                @Override
                protected JSch createDefaultJSch(FS fs) throws JSchException {
                    JSch jsch = super.createDefaultJSch(fs);
                    try {
                        jsch.addIdentity(auth.getSshKey(), auth.getPassphrase().getBytes());
                    } catch (JSchException e) {
                        throw new RuntimeException("Failed to add SSH identity", e);
                    }
                    return jsch;
                }
            };
            sshTransport.setSshSessionFactory(sshSessionFactory);
        } catch (Exception e) {
            log.error("配置SSH传输失败", e);
            throw new RuntimeException("配置SSH认证失败", e);
        }
    }
}